﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Base.Util;
using System.Text.RegularExpressions;
using Base.DAL;
using System.Collections.Concurrent;

namespace Base.BLL
{
    public class DataParseService
    {
        #region 属性
        /// <summary>
        /// 测区编号
        /// </summary>
        private int cqbh;
        /// <summary>
        /// 串口数据（字符串格式）
        /// </summary>
        private string strWhole;
        /// <summary>
        /// 上一次计算加权平均值的时间
        /// </summary>
        private static List<SYSTEMCALC> lastCalcT = new List<SYSTEMCALC>();
        /// <summary>
        /// 缓冲区
        /// </summary>
        private static Dictionary<int, string> cache = new Dictionary<int, string>();
        private static Dictionary<int, List<byte>> cacheByte = new Dictionary<int, List<byte>>();
        /// <summary>
        /// 解析器
        /// </summary>
        private static Dictionary<DATA_TYPE, IDataParser> parsers;
        /// <summary>
        /// 解析器集合
        /// </summary>
        public static Dictionary<DATA_TYPE, IDataParser> Parsers{get{return parsers;}}

        /// <summary>
        /// 最新数据缓存池
        /// </summary>
        private static Dictionary<DATA_TYPE, IEnumerable<IEntity>> lastDataPool = new Dictionary<DATA_TYPE, IEnumerable<IEntity>>();

        private static bool loaded = false;
        #endregion
        /// <summary>
        /// 缓冲区最大长度，超过此长度未识别则清空缓冲区
        /// </summary>
        public static int MaxLen { get; set; } = 10240;
        /// <summary>
        /// 定义解析出数据要执行的委托
        /// </summary>
        /// <param name="type"></param>
        /// <param name="data"></param>
        public delegate void OnDataParsed(DATA_TYPE type,object data);

        public event OnDataParsed DataParsed;

        /// <summary>
        /// 初始化解析器，为每个类型传感器添加一个解析器
        /// </summary>
        static DataParseService()
        {
            Load();
        }

        public static void Load()
        {
            if (loaded)
            {
                return;
            }
            ConfigService.Load();
            parsers = new Dictionary<DATA_TYPE, IDataParser>();
            parsers.Add(DATA_TYPE.ZCSJ, new DataParser4ZC());
            parsers.Add(DATA_TYPE.DBLC, new DataParser4DBLC());
            parsers.Add(DATA_TYPE.MGYL, new DataParser4MGYL());
            parsers.Add(DATA_TYPE.CQYL, new DataParser4CQYL());

            //初始化加权平均值时间，先从数据库临时表中查找，如果没有则设为当前时间
            DateTime dt = DateTime.Now;
            if (Db.Count<SYSTEMCALC>() == 0)
            {
                lastCalcT.Add(new SYSTEMCALC { HSPAN = 2, CDATETIME = dt });
                lastCalcT.Add(new SYSTEMCALC { HSPAN = 4, CDATETIME = dt });
                lastCalcT.Add(new SYSTEMCALC { HSPAN = 8, CDATETIME = dt });
                lastCalcT.Add(new SYSTEMCALC { HSPAN = 12, CDATETIME = dt });
                lastCalcT.Add(new SYSTEMCALC { HSPAN = 24, CDATETIME = dt });
                Db.Insert<SYSTEMCALC>(lastCalcT);
            }
            else
            {
                lastCalcT = Db.Query<SYSTEMCALC>().ToList();
            }

            //从数据库中加载最新数据            
            lastDataPool.Add(DATA_TYPE.ZCSJ, Db.QueryWhere<View_ZC_Active>("1=1 ORDER BY CQBH,GZMBH,ZBH"));
            lastDataPool.Add(DATA_TYPE.DBLC, Db.QueryWhere<View_DBLC_Active>("1=1 ORDER BY CQBH,XDBH,LCBH"));
            lastDataPool.Add(DATA_TYPE.MGYL, Db.QueryWhere<View_MG_Active>("1=1 ORDER BY CQBH,XDBH,MBH"));
            lastDataPool.Add(DATA_TYPE.CQYL, Db.QueryWhere<View_CQYL_Active>("1=1 ORDER BY CQBH,XDBH,CQYLBH"));
            loaded = true;
        }
        public DataParseService(int cqbh,byte[] bits)
        {
            this.cqbh = cqbh;
            strWhole = Encoding.Default.GetString(bits);
            if (cache.ContainsKey(cqbh))
            {
                cache[cqbh] += strWhole;
                cacheByte[cqbh].AddRange(bits);
            }
            else
            {
                cache[cqbh] = strWhole;
                cacheByte[cqbh] = new List<byte>(bits);
            }
        }
        public bool IsCorrect()
        {
            if (parsers.Count() == 0)
            {
                throw new Exception("未添加数据解析器");
            }
            string pattern = @"^(\*\*\d+S(";
            for (int i=0;i<parsers.Count();i++)
            {
                if (i > 0)
                {
                    pattern += "|";
                }
                var p = parsers.ElementAt(i).Value;
                pattern+="("+p.RegexPattern()+@"\r)";
                
            }
            pattern += @")+E.{2}OW\r*\n*)+$";
            if (Regex.IsMatch(strWhole, pattern) && Check())
            {
                return true;
            }
            Console.WriteLine("丢弃错误的数据格式");
            return false;
        }

        //校验数据
        public bool Check()
        {
            return true;
        }

        public void Parse()
        {
            string strCache = cache[cqbh];
            List<byte> byteCache = cacheByte[cqbh];
            #region 以字符串进行解析，弃用
            //GroupCollection matches = Regex.Match(strCache, @"(\s\S)*(\*\*\d+S.+OW)(\s\S)*").Groups;
            //if (strCache.Length > MaxLen)
            //{
            //    cache[cqbh] = "";
            //    return;
            //}
            //if (matches.Count == 1)
            //{
            //    return;
            //}
            //strWhole = matches[2].Value;
            //string warn = "测区" + cqbh + "接收到错误的数据" + ComHelper.strToHexStr(strWhole);
            //cache[cqbh] = matches[3].Value;
            #endregion
            cache[cqbh]="";

            if (byteCache.Count>MaxLen)
            {
                cacheByte[cqbh].Clear();
                return;
            }
            //在字节中查找，以**为起始，OW为结束
            int start = -1, end = -1;
            for (int i=0;i< byteCache.Count-1;i++)
            {
                if(byteCache[i]==0x2A && byteCache[i+1] == 0x2A)
                {
                    start = i;
                    for (int j =byteCache.Count - 1;j>0; j--)
                    {
                        if (byteCache[j-1] == 0x4F && byteCache[j] == 0x57)
                        {
                            end = j;
                            break;
                        }
                    }
                    if(end!=-1)
                    {
                        break;
                    }
                }
            }
            if(start==-1 || end==-1)
            {
                return;
            }
            strWhole= Encoding.Default.GetString(byteCache.GetRange(start, end - start+1).ToArray());
            string warn = "测区" + cqbh + "接收到错误的数据" + ComHelper.byteToHexStr(cacheByte[cqbh].ToArray());
            cacheByte[cqbh] = byteCache.GetRange(end + 1, byteCache.Count - end - 1);
            if (!IsCorrect())
            {
                LoggerHelper.Warn(warn);
                return;
            }            
            
            //去除**1S
            string _data = Regex.Replace(strWhole, @"\*\*\d+S", "\r");
            string[] data = _data.Split(new string[] { "\r" }, StringSplitOptions.RemoveEmptyEntries);
            DateTime dt=DateTime.Now;
            for (int i=0;i<data.Count()-1;i++)
            {
                foreach (var p in parsers)
                {
                    object d = p.Value.Parse(cqbh,data[i],dt,lastDataPool[p.Key]);
                    if (d != null && DataParsed!=null)
                    {
                        DataParsed(p.Key,d);
                        break;
                    }
                }
            }
            //存储最新数据
            foreach (var p in parsers)
            {
                p.Value.StorageCur(lastDataPool[p.Key]);
            }
        }
        /// <summary>
        /// 如果需要计算，则计算加权平均值并保存
        /// </summary>
        public static void Calc()
        {
            DateTime dt = DateTime.Now;
            foreach (var c in lastCalcT)
            {
                int hSpan = c.HSPAN;
                DateTime lastT = c.CDATETIME;
                DateTime nextT = lastT.Date + new TimeSpan((lastT.Hour / hSpan + 1) * hSpan, 0, 0);
                //跳过不需要计算的情况
                if (dt<nextT)
                {
                    continue;
                }
                //计算加权平均值
                foreach (var p in parsers)
                {
                    p.Value.Calc(lastT, dt, hSpan);
                }
                //更新
                c.CDATETIME = dt;
                Db.Update(c);
            }            
        }
        /// <summary>
        /// 计算加权平均值并保存
        /// </summary>
        public static void CalcAnyway()
        {
            DateTime dt = DateTime.Now;
            foreach (var c in lastCalcT)
            {
                int hSpan = c.HSPAN;
                DateTime lastT = c.CDATETIME;
                foreach (var p in parsers)
                {
                    p.Value.Calc(lastT, dt, hSpan);
                }
                c.CDATETIME = dt;
            }
            //更新
            Db.Update<SYSTEMCALC>(lastCalcT);
        }
        /// <summary>
        /// 根据数据类型从缓存中读取当前数据，同时把数据存储至数据库
        /// </summary>
        /// <param name="type">数据类型</param>
        /// <returns>当前数据列表</returns>
        public static IEnumerable<IEntity> GetCache(DATA_TYPE type)
        {
            //存储最新数据
            //foreach (var p in parsers)
            //{
            //    p.Value.StorageCur(lastDataPool[p.Key]);
            //}
            //parsers[type].StorageCur(lastDataPool[type]);
            //从数据库中读取
            switch (type)
            {
                case DATA_TYPE.ZCSJ:
                    return Db.QueryWhere<View_ZC_Active>("1=1 ORDER BY CQBH,GZMBH,ZBH");
                case DATA_TYPE.DBLC:
                    return Db.QueryWhere<View_DBLC_Active>("1=1 ORDER BY CQBH,XDBH,LCBH");
                case DATA_TYPE.MGYL:
                    return Db.QueryWhere<View_MG_Active>("1=1 ORDER BY CQBH,XDBH,MBH");
                case DATA_TYPE.CQYL:
                    return Db.QueryWhere<View_CQYL_Active>("1=1 ORDER BY CQBH,XDBH,CQYLBH");
                default:
                    return new List<IEntity>();
            }
            //return lastDataPool[type];
        }
    }

    public enum DATA_TYPE
    {
        ZCSJ,//综采数据
        DBLC,//顶板离层数据
        MGYL,//锚杆应力
        CQYL//测区应力
    }    
}
